using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using UserManagement;
using WindowsFormsApp1;
using System.Configuration;
using System.Drawing;

namespace AlarmCSharpDemo
{
    public partial class AlarmDemo : Form
    {
        private Int32 m_lUserID = -1;
        private Int32[] m_lAlarmHandle = new Int32[200];
        private Int32 iListenHandle = -1;
        private int iDeviceNumber = 0; //添加设备个数
        private int iFileNumber = 0; //保存的文件个数
        private uint iLastErr = 0;
        private string strErr;
        private TcpClientHelper tcpClient; // TCP客户端工具

        public CHCNetSDK.LOGINRESULTCALLBACK LoginCallBack = null;
        private CHCNetSDK.EXCEPYIONCALLBACK m_fExceptionCB = null;
        private CHCNetSDK.MSGCallBack_V31 m_falarmData_V31 = null;
        private CHCNetSDK.MSGCallBack m_falarmData = null;

        public delegate void UpdateTextStatusCallback(string strLogStatus, IntPtr lpDeviceInfo);
        public delegate void UpdateListBoxCallback(string strAlarmTime, string strDevIP, string strAlarmMsg);
        public delegate void UpdateListBoxCallbackException(string strAlarmTime, int lUserID, string strAlarmMsg);

        CHCNetSDK.NET_VCA_TRAVERSE_PLANE m_struTraversePlane = new CHCNetSDK.NET_VCA_TRAVERSE_PLANE();
        CHCNetSDK.NET_VCA_AREA m_struVcaArea = new CHCNetSDK.NET_VCA_AREA();
        CHCNetSDK.NET_VCA_INTRUSION m_struIntrusion = new CHCNetSDK.NET_VCA_INTRUSION();
        CHCNetSDK.UNION_STATFRAME m_struStatFrame = new CHCNetSDK.UNION_STATFRAME();
        CHCNetSDK.UNION_STATTIME m_struStatTime = new CHCNetSDK.UNION_STATTIME();
        public AlarmDemo()
        {
            InitializeComponent();

            // 初始化TCP客户端
            tcpClient = new TcpClientHelper("localhost", 8888, 5000);
            bool m_bInitSDK = CHCNetSDK.NET_DVR_Init();
            if (m_bInitSDK == false)
            {
                MessageBox.Show("NET_DVR_Init error!");
                return;
            }
            else
            {
                byte[] strIP = new byte[16 * 16];
                uint dwValidNum = 0;
                Boolean bEnableBind = false;

                //获取本地PC网卡IP信息
                if (CHCNetSDK.NET_DVR_GetLocalIP(strIP, ref dwValidNum, ref bEnableBind))
                {
                    if (dwValidNum > 0)
                    {
                        //取第一张网卡的IP地址为默认监听端口
                        textBoxListenIP.Text = System.Text.Encoding.UTF8.GetString(strIP, 0, 16);
                        //CHCNetSDK.NET_DVR_SetValidIP(0,true); //绑定第一张网卡
                    }
                }

                //保存SDK日志 To save the SDK log
                CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);

                //设置透传报警信息类型
                CHCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struLocalCfg = new CHCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
                struLocalCfg.byAlarmJsonPictureSeparate = 1;//控制JSON透传报警数据和图片是否分离，0-不分离(COMM_VCA_ALARM返回)，1-分离（分离后走COMM_ISAPI_ALARM回调返回）

                Int32 nSize = Marshal.SizeOf(struLocalCfg);
                IntPtr ptrLocalCfg = Marshal.AllocHGlobal(nSize);
                Marshal.StructureToPtr(struLocalCfg, ptrLocalCfg, false);

                if (!CHCNetSDK.NET_DVR_SetSDKLocalCfg(17, ptrLocalCfg))  //NET_DVR_LOCAL_CFG_TYPE_GENERAL
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    strErr = "NET_DVR_SetSDKLocalCfg failed, error code= " + iLastErr;
                    MessageBox.Show(strErr);
                }
                Marshal.FreeHGlobal(ptrLocalCfg);

                for (int i = 0; i < 200; i++)
                {
                    m_lAlarmHandle[i] = -1;
                }

                //设置异常消息回调函数
                if (m_fExceptionCB == null)
                {
                    m_fExceptionCB = new CHCNetSDK.EXCEPYIONCALLBACK(cbExceptionCB);
                }
                CHCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, IntPtr.Zero, m_fExceptionCB, IntPtr.Zero);


                //设置报警回调函数
                if (m_falarmData_V31 == null)
                {
                    m_falarmData_V31 = new CHCNetSDK.MSGCallBack_V31(MsgCallback_V31);
                }
                CHCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(m_falarmData_V31, IntPtr.Zero);
            }
        }

        public void UpdateClientListException(string strAlarmTime, int lUserID, string strAlarmMsg)
        {
            //异常设备信息
            string strDevIP = "";
            for (int i = 0; i < iDeviceNumber; i++)
            {
                m_lUserID = Int32.Parse(listViewDevice.Items[i].SubItems[0].Text);
                if (m_lUserID == lUserID)
                {
                    strDevIP = listViewDevice.Items[i].SubItems[1].Text.TrimEnd('\0');
                }
            }

            //列表新增报警信息
            listViewAlarmInfo.Items.Add(new ListViewItem(new string[] { strAlarmTime, strDevIP, strAlarmMsg }));

        }

        public void cbExceptionCB(uint dwType, int lUserID, int lHandle, IntPtr pUser)
        {
            //异常消息信息类型
            string stringAlarm = "异常消息回调，信息类型：0x" + Convert.ToString(dwType, 16) + ", lUserID:" + lUserID + ", lHandle:" + lHandle;

            if (InvokeRequired)
            {
                object[] paras = new object[3];
                paras[0] = DateTime.Now.ToString(); //当前PC系统时间
                paras[1] = lUserID;
                paras[2] = stringAlarm;
                listViewAlarmInfo.BeginInvoke(new UpdateListBoxCallbackException(UpdateClientListException), paras);
            }
            else
            {
                //创建该控件的主线程直接更新信息列表 
                UpdateClientListException(DateTime.Now.ToString(), lUserID, stringAlarm);
            }
        }

        public bool MsgCallback_V31(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            //通过lCommand来判断接收到的报警信息类型，不同的lCommand对应不同的pAlarmInfo内容
            AlarmMessageHandle(lCommand, ref pAlarmer, pAlarmInfo, dwBufLen, pUser);

            return true; //回调函数需要有返回，表示正常接收到数据
        }

        public void MsgCallback(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            //通过lCommand来判断接收到的报警信息类型，不同的lCommand对应不同的pAlarmInfo内容
            AlarmMessageHandle(lCommand, ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
        }

        public void AlarmMessageHandle(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            //通过lCommand来判断接收到的报警信息类型，不同的lCommand对应不同的pAlarmInfo内容
            switch (lCommand)
            {
                case CHCNetSDK.COMM_ALARM_ACS://门禁主机报警上传
                    ProcessCommAlarm_AcsAlarm(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                    break;
                default:
                    {
                        //报警设备IP地址
                        string strIP = System.Text.Encoding.UTF8.GetString(pAlarmer.sDeviceIP).TrimEnd('\0');

                        //报警信息类型
                        string stringAlarm = "报警上传，信息类型：0x" + Convert.ToString(lCommand, 16);

                        if (InvokeRequired)
                        {
                            object[] paras = new object[3];
                            paras[0] = DateTime.Now.ToString(); //当前PC系统时间
                            paras[1] = strIP;
                            paras[2] = stringAlarm;
                            listViewAlarmInfo.BeginInvoke(new UpdateListBoxCallback(UpdateClientList), paras);
                        }
                        else
                        {
                            //创建该控件的主线程直接更新信息列表 
                            UpdateClientList(DateTime.Now.ToString(), strIP, stringAlarm);
                        }
                    }
                    break;
            }
        }

        private void ProcessCommAlarm_AcsAlarm(ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            CHCNetSDK.NET_DVR_ACS_ALARM_INFO struAcsAlarm = new CHCNetSDK.NET_DVR_ACS_ALARM_INFO();
            uint dwSize = (uint)Marshal.SizeOf(struAcsAlarm);
            struAcsAlarm = (CHCNetSDK.NET_DVR_ACS_ALARM_INFO)Marshal.PtrToStructure(pAlarmInfo, typeof(CHCNetSDK.NET_DVR_ACS_ALARM_INFO));

            //报警设备IP地址
            string strIP = System.Text.Encoding.UTF8.GetString(pAlarmer.sDeviceIP).TrimEnd('\0');

            //保存抓拍图片
            if ((struAcsAlarm.dwPicDataLen != 0) && (struAcsAlarm.pPicData != IntPtr.Zero))
            {
                string str = ".\\picture\\Device_Acs_CapturePic_[" + strIP + "]_lUerID_[" + pAlarmer.lUserID + "]_" + iFileNumber + ".jpg";
                FileStream fs = new FileStream(str, FileMode.Create);
                int iLen = (int)struAcsAlarm.dwPicDataLen;
                byte[] by = new byte[iLen];
                Marshal.Copy(struAcsAlarm.pPicData, by, 0, iLen);
                fs.Write(by, 0, iLen);
                fs.Close();
                iFileNumber++;
            }

            //报警时间：年月日时分秒
            string strTimeYear = (struAcsAlarm.struTime.dwYear).ToString();
            string strTimeMonth = (struAcsAlarm.struTime.dwMonth).ToString("d2");
            string strTimeDay = (struAcsAlarm.struTime.dwDay).ToString("d2");
            string strTimeHour = (struAcsAlarm.struTime.dwHour).ToString("d2");
            string strTimeMinute = (struAcsAlarm.struTime.dwMinute).ToString("d2");
            string strTimeSecond = (struAcsAlarm.struTime.dwSecond).ToString("d2");
            string strTime = strTimeYear + "-" + strTimeMonth + "-" + strTimeDay + " " + strTimeHour + ":" + strTimeMinute + ":" + strTimeSecond;

            string stringAlarm = "门禁主机报警信息，dwMajor：0x" + Convert.ToString(struAcsAlarm.dwMajor, 16) + "，dwMinor：0x" +
                Convert.ToString(struAcsAlarm.dwMinor, 16) + "，卡号：" + System.Text.Encoding.UTF8.GetString(struAcsAlarm.struAcsEventInfo.byCardNo).TrimEnd('\0')
                + "，读卡器编号：" + struAcsAlarm.struAcsEventInfo.dwCardReaderNo + "，报警触发时间：" + strTime +
                "，事件流水号：" + struAcsAlarm.struAcsEventInfo.dwSerialNo;

            if (struAcsAlarm.byAcsEventInfoExtend == 1)
            {
                CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND struInfoExtend = new CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND();
                uint dwSizeEx = (uint)Marshal.SizeOf(struInfoExtend);
                struInfoExtend = (CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND)Marshal.PtrToStructure(struAcsAlarm.pAcsEventInfoExtend, typeof(CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND));
                stringAlarm = stringAlarm + ", 工号:" + System.Text.Encoding.UTF8.GetString(struInfoExtend.byEmployeeNo).TrimEnd('\0') +
                    ", 人员类型:" + struInfoExtend.byUserType;
                string empNo = System.Text.Encoding.UTF8.GetString(struInfoExtend.byEmployeeNo).TrimEnd('\0');
                if (empNo == "") return;
                var UserInfo = this.SearchUserInfo(empNo);

                // 如果UserInfo不为null，推送数据到WorkPieceDataCapture
                if (UserInfo != null)
                {
                    SendEmployeeDataToWorkPiece(UserInfo);
                }

                stringAlarm = "UserInfo:" + UserInfo + ";" + stringAlarm;
            }

            if (struAcsAlarm.byAcsEventInfoExtendV20 == 1)
            {
                CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND_V20 struInfoExtendV20 = new CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND_V20();
                uint dwSizeEx = (uint)Marshal.SizeOf(struInfoExtendV20);
                struInfoExtendV20 = (CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND_V20)Marshal.PtrToStructure(struAcsAlarm.pAcsEventInfoExtendV20, typeof(CHCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND_V20));
                stringAlarm = stringAlarm + ", 温度:" + struInfoExtendV20.fCurrTemperature + ", 是否异常温度:" + struInfoExtendV20.byIsAbnomalTemperature
                    + ", 是否需要核验:" + struInfoExtendV20.byRemoteCheck;

                if (struInfoExtendV20.byRemoteCheck == 2)
                {
                    //建议另外建线程或者使用消息队列进行处理和下发核验结果给设备，避免阻塞回调
                    //ACS_remoteCheck(struAcsAlarm.struAcsEventInfo.dwSerialNo);
                }

                //保存热成像图片
                if ((struInfoExtendV20.dwThermalDataLen != 0) && (struInfoExtendV20.pThermalData != IntPtr.Zero))
                {
                    string str = ".\\picture\\Device_Acs_ThermalData_[" + strIP + "]_lUerID_[" + pAlarmer.lUserID + "]_" + iFileNumber + ".jpg";
                    FileStream fs = new FileStream(str, FileMode.Create);
                    int iLen = (int)struInfoExtendV20.dwThermalDataLen;
                    byte[] by = new byte[iLen];
                    Marshal.Copy(struInfoExtendV20.pThermalData, by, 0, iLen);
                    fs.Write(by, 0, iLen);
                    fs.Close();
                    iFileNumber++;
                }
            }

            if (InvokeRequired)
            {
                object[] paras = new object[3];
                paras[0] = DateTime.Now.ToString(); //当前PC系统时间
                paras[1] = strIP;
                paras[2] = stringAlarm;
                listViewAlarmInfo.BeginInvoke(new UpdateListBoxCallback(UpdateClientList), paras);
            }
            else
            {
                //创建该控件的主线程直接更新信息列表 
                UpdateClientList(DateTime.Now.ToString(), strIP, stringAlarm);
            }
        }

        public void UpdateClientList(string strAlarmTime, string strDevIP, string strAlarmMsg)
        {
            //列表新增报警信息
            listViewAlarmInfo.Items.Add(new ListViewItem(new string[] { strAlarmTime, strDevIP, strAlarmMsg }));
        }

        public void UpdateClientList(string strLogStatus, IntPtr lpDeviceInfo)
        {
            //列表新增报警信息
            labelLogin.Text = "登录状态（异步）：" + strLogStatus;
        }

        public void cbLoginCallBack(int lUserID, int dwResult, IntPtr lpDeviceInfo, IntPtr pUser)
        {
            string strLoginCallBack = "登录设备，lUserID：" + lUserID + "，dwResult：" + dwResult;

            if (dwResult == 0)
            {
                uint iErrCode = CHCNetSDK.NET_DVR_GetLastError();
                strLoginCallBack = strLoginCallBack + "，错误号:" + iErrCode;
            }

            //下面代码注释掉也会崩溃
            if (InvokeRequired)
            {
                object[] paras = new object[2];
                paras[0] = strLoginCallBack;
                paras[1] = lpDeviceInfo;
                labelLogin.BeginInvoke(new UpdateTextStatusCallback(UpdateClientList), paras);
            }
            else
            {
                //创建该控件的主线程直接更新信息列表 
                UpdateClientList(strLoginCallBack, lpDeviceInfo);
            }
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            if (textBoxIP.Text == "" || textBoxPort.Text == "" || textBoxUserName.Text == "" || textBoxPassword.Text == "")
            {
                MessageBox.Show("Please input IP, Port, User name and Password!");
                return;
            }

            if (iDeviceNumber >= 20)
            {
                MessageBox.Show("本程序限制最多添加20台设备！");
                return;
            }

            CHCNetSDK.NET_DVR_USER_LOGIN_INFO struLogInfo = new CHCNetSDK.NET_DVR_USER_LOGIN_INFO();

            //设备IP地址或者域名
            byte[] byIP = System.Text.Encoding.Default.GetBytes(textBoxIP.Text);
            struLogInfo.sDeviceAddress = new byte[129];
            byIP.CopyTo(struLogInfo.sDeviceAddress, 0);

            //设备用户名
            byte[] byUserName = System.Text.Encoding.Default.GetBytes(textBoxUserName.Text);
            struLogInfo.sUserName = new byte[64];
            byUserName.CopyTo(struLogInfo.sUserName, 0);

            //设备密码
            byte[] byPassword = System.Text.Encoding.Default.GetBytes(textBoxPassword.Text);
            struLogInfo.sPassword = new byte[64];
            byPassword.CopyTo(struLogInfo.sPassword, 0);

            struLogInfo.wPort = ushort.Parse(textBoxPort.Text);//设备服务端口号

            struLogInfo.cbLoginResult = LoginCallBack;
            struLogInfo.bUseAsynLogin = false; //是否异步登录：0- 否，1- 是 

            if ((struLogInfo.bUseAsynLogin == true) && (LoginCallBack == null))
            {
                LoginCallBack = new CHCNetSDK.LOGINRESULTCALLBACK(cbLoginCallBack);//注册回调函数                    
            }

            struLogInfo.byLoginMode = 0; //0-Private, 1-ISAPI, 2-自适应
            struLogInfo.byHttps = 0; //0-不适用tls，1-使用tls 2-自适应

            CHCNetSDK.NET_DVR_DEVICEINFO_V40 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V40();

            //登录设备 Login the device
            m_lUserID = CHCNetSDK.NET_DVR_Login_V40(ref struLogInfo, ref DeviceInfo);
            if (m_lUserID < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                strErr = "NET_DVR_Login_V30 failed, error code= " + iLastErr; //登录失败，输出错误号 Failed to login and output the error code
                MessageBox.Show(strErr);
            }
            else
            {
                //登录成功
                iDeviceNumber++;
                string str1 = "" + m_lUserID;
                listViewDevice.Items.Add(new ListViewItem(new string[] { str1, textBoxIP.Text, "未布防" }));//将已注册设备添加进列表
            }
        }

        private void btn_SetAlarm_Click(object sender, EventArgs e)
        {
            CHCNetSDK.NET_DVR_SETUPALARM_PARAM struAlarmParam = new CHCNetSDK.NET_DVR_SETUPALARM_PARAM();
            struAlarmParam.dwSize = (uint)Marshal.SizeOf(struAlarmParam);
            struAlarmParam.byLevel = 1; //0- 一级布防,1- 二级布防
            struAlarmParam.byAlarmInfoType = 1;//智能交通设备有效，新报警信息类型
            struAlarmParam.byFaceAlarmDetection = 1;//1-人脸侦测

            for (int i = 0; i < iDeviceNumber; i++)
            {
                m_lUserID = Int32.Parse(listViewDevice.Items[i].SubItems[0].Text);
                m_lAlarmHandle[m_lUserID] = CHCNetSDK.NET_DVR_SetupAlarmChan_V41(m_lUserID, ref struAlarmParam);
                if (m_lAlarmHandle[m_lUserID] < 0)
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    strErr = "布防失败，错误号：" + iLastErr; //布防失败，输出错误号
                    listViewDevice.Items[i].SubItems[2].Text = strErr;
                }
                else
                {
                    listViewDevice.Items[i].SubItems[2].Text = "布防成功";
                }
                btn_SetAlarm.Enabled = false;
            }
        }

        private void btnCloseAlarm_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < iDeviceNumber; i++)
            {
                m_lUserID = Int32.Parse(listViewDevice.Items[i].SubItems[0].Text);
                if (m_lAlarmHandle[m_lUserID] >= 0)
                {
                    if (!CHCNetSDK.NET_DVR_CloseAlarmChan_V30(m_lAlarmHandle[m_lUserID]))
                    {
                        iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                        strErr = "撤防失败，错误号：" + iLastErr; //撤防失败，输出错误号
                        listViewDevice.Items[i].SubItems[2].Text = strErr;
                    }
                    else
                    {
                        listViewDevice.Items[i].SubItems[2].Text = "未布防";
                        m_lAlarmHandle[i] = -1;
                    }
                }
                else
                {
                    listViewDevice.Items[i].SubItems[2].Text = "未布防";
                }
            }
            btn_SetAlarm.Enabled = true;
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            //撤防
            btnCloseAlarm_Click(sender, e);

            //停止监听
            if (iListenHandle >= 0)
            {
                CHCNetSDK.NET_DVR_StopListen_V30(iListenHandle);
            }

            //注销登录
            for (int i = 0; i < iDeviceNumber; i++)
            {
                m_lUserID = Int32.Parse(listViewDevice.Items[i].SubItems[0].Text);
                CHCNetSDK.NET_DVR_Logout(m_lUserID);
            }

            //释放SDK资源，在程序结束之前调用
            CHCNetSDK.NET_DVR_Cleanup();

            Application.Exit();
        }

        private void listViewDevice_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (listViewDevice.SelectedItems.Count > 0)
                {
                    if (DialogResult.OK == MessageBox.Show("请确认是否删除所选择的设备！", "删除提示", MessageBoxButtons.OKCancel))
                    {
                        foreach (ListViewItem item in this.listViewDevice.SelectedItems)
                        {
                            if (item.Selected)
                            {
                                m_lUserID = Int32.Parse(item.SubItems[0].Text);
                                CHCNetSDK.NET_DVR_CloseAlarmChan_V30(m_lAlarmHandle[m_lUserID]);
                                CHCNetSDK.NET_DVR_Logout(m_lUserID);
                                item.Remove();
                                iDeviceNumber--;
                            }
                        }
                        this.listViewDevice.Refresh();
                    }
                }
                else
                {

                }
            }
        }

        public Int32 m_lGetUserCfgHandle = -1;
        public Int32 m_lSetUserCfgHandle = -1;
        public Int32 m_lDelUserCfgHandle = -1;
        private EmployeeData SearchUserInfo(string strEmployeeNo)
        {
            if (m_lGetUserCfgHandle != -1)
            {
                if (CHCNetSDK.NET_DVR_StopRemoteConfig(m_lGetUserCfgHandle))
                {
                    m_lGetUserCfgHandle = -1;
                }
            }

            string sURL = "POST /ISAPI/AccessControl/UserInfo/Search?format=json";
            IntPtr ptrURL = Marshal.StringToHGlobalAnsi(sURL);
            m_lSetUserCfgHandle = CHCNetSDK.NET_DVR_StartRemoteConfig(m_lUserID, CHCNetSDK.NET_DVR_JSON_CONFIG, ptrURL, sURL.Length, null, IntPtr.Zero);
            if (m_lSetUserCfgHandle < 0)
            {
                MessageBox.Show("NET_DVR_StartRemoteConfig fail [url:POST /ISAPI/AccessControl/UserInfo/Search?format=json] error:" + CHCNetSDK.NET_DVR_GetLastError());
                Marshal.FreeHGlobal(ptrURL);
                return null;
            }
            else
            {
                CUserInfoSearchCondCfg JsonUserInfoSearchCondCfg = new CUserInfoSearchCondCfg();
                JsonUserInfoSearchCondCfg.UserInfoSearchCond = new CUserInfoSearchCond();
                JsonUserInfoSearchCondCfg.UserInfoSearchCond.searchID = "2";
                JsonUserInfoSearchCondCfg.UserInfoSearchCond.searchResultPosition = 0;
                JsonUserInfoSearchCondCfg.UserInfoSearchCond.maxResults = 1000;
                JsonUserInfoSearchCondCfg.UserInfoSearchCond.EmployeeNoList = new List<CEmployeeNoList>();
                CEmployeeNoList singleEmployeeNoList = new CEmployeeNoList();
                singleEmployeeNoList.employeeNo = strEmployeeNo;
                JsonUserInfoSearchCondCfg.UserInfoSearchCond.EmployeeNoList.Add(singleEmployeeNoList);
                string strUserInfoSearchCondCfg = JsonConvert.SerializeObject(JsonUserInfoSearchCondCfg);
                IntPtr ptrUserInfoSearchCondCfg = Marshal.StringToHGlobalAnsi(strUserInfoSearchCondCfg);

                IntPtr ptrJsonData = Marshal.AllocHGlobal(1024);
                for (int i = 0; i < 1024; i++)
                {
                    Marshal.WriteByte(ptrJsonData, i, 0);
                }

                int dwState = (int)CHCNetSDK.NET_SDK_SENDWITHRECV_STATUS.NET_SDK_CONFIG_STATUS_SUCCESS;
                uint dwReturned = 0;
                while (true)
                {
                    dwState = CHCNetSDK.NET_DVR_SendWithRecvRemoteConfig(m_lSetUserCfgHandle, ptrUserInfoSearchCondCfg, (uint)strUserInfoSearchCondCfg.Length, ptrJsonData, 1024, ref dwReturned);

                    if (dwState == (int)CHCNetSDK.NET_SDK_SENDWITHRECV_STATUS.NET_SDK_CONFIG_STATUS_NEEDWAIT)
                    {
                        Thread.Sleep(10);
                        continue;
                    }
                    else if (dwState == (int)CHCNetSDK.NET_SDK_SENDWITHRECV_STATUS.NET_SDK_CONFIG_STATUS_FAILED)
                    {
                        MessageBox.Show("Get User Fail error:" + CHCNetSDK.NET_DVR_GetLastError());
                    }
                    else if (dwState == (int)CHCNetSDK.NET_SDK_SENDWITHRECV_STATUS.NET_SDK_CONFIG_STATUS_SUCCESS)
                    {
                        byte[] bUserInfoSearch = new byte[1024 * 10];
                        Marshal.Copy(ptrJsonData, bUserInfoSearch, 0, (int)dwReturned);
                        string strUserInfoSearch = System.Text.Encoding.UTF8.GetString(bUserInfoSearch);

                        CUserInfoSearchCfg JsonUserInfoSearchCfg = new CUserInfoSearchCfg();
                        JsonUserInfoSearchCfg = JsonConvert.DeserializeObject<CUserInfoSearchCfg>(strUserInfoSearch);
                        if (JsonUserInfoSearchCfg.UserInfoSearch == null)
                        {
                            //null说明返回的Json报文不是UserInfoSearch，而是ResponseStatus
                            CResponseStatus JsonResponseStatus = new CResponseStatus();
                            JsonResponseStatus = JsonConvert.DeserializeObject<CResponseStatus>(strUserInfoSearch);
                            if (JsonResponseStatus.statusCode == 1)
                            {
                                MessageBox.Show("Get User Success");
                            }
                            else
                            {
                                MessageBox.Show("Get User Fail, ResponseStatus.statusCode" + JsonResponseStatus.statusCode);
                            }
                        }
                        else
                        {
                            //解析UserInfoSearch报文
                            if (JsonUserInfoSearchCfg.UserInfoSearch.totalMatches == 0)
                            {
                                MessageBox.Show("no this EmployeeNo person");
                                break;
                            }
                            for (int i = 0; i < JsonUserInfoSearchCfg.UserInfoSearch.numOfMatches;)
                            {
                                var userInfo = new EmployeeData();
                                userInfo.EmployeeId = JsonUserInfoSearchCfg.UserInfoSearch.UserInfo[i].employeeNo ?? "";
                                userInfo.EmployeeName = JsonUserInfoSearchCfg.UserInfoSearch.UserInfo[i].name ?? "";
                                userInfo.EmployeeType = JsonUserInfoSearchCfg.UserInfoSearch.UserInfo[i].userType ?? "";
                                return userInfo;
                            }
                        }
                        break;
                    }
                    else if (dwState == (int)CHCNetSDK.NET_SDK_SENDWITHRECV_STATUS.NET_SDK_CONFIG_STATUS_FINISH)
                    {
                        MessageBox.Show("Get User Finish");
                        break;
                    }
                    else if (dwState == (int)CHCNetSDK.NET_SDK_SENDWITHRECV_STATUS.NET_SDK_CONFIG_STATUS_EXCEPTION)
                    {
                        MessageBox.Show("Get User Exception error:" + CHCNetSDK.NET_DVR_GetLastError());
                        break;
                    }
                    else
                    {
                        MessageBox.Show("unknown status error:" + CHCNetSDK.NET_DVR_GetLastError());
                        break;
                    }
                }
                Marshal.FreeHGlobal(ptrUserInfoSearchCondCfg);
                Marshal.FreeHGlobal(ptrJsonData);
                return null;
            }
        }

        /// <summary>
        /// 发送员工数据到WorkPieceDataCapture
        /// </summary>
        /// <param name="employeeData">员工数据</param>
        private void SendEmployeeDataToWorkPiece(EmployeeData employeeData)
        {
            try
            {
                // 添加当前时间作为登录时间
                employeeData.LoginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                // 异步发送数据，避免阻塞考勤事件处理
                System.Threading.Tasks.Task.Run(() =>
                {
                    bool success = tcpClient.SendEmployeeData(employeeData);
                    if (success)
                    {
                        Console.WriteLine($"成功推送员工数据: {employeeData.EmployeeName}({employeeData.EmployeeId})");
                    }
                    else
                    {
                        Console.WriteLine($"推送员工数据失败: {employeeData.EmployeeName}({employeeData.EmployeeId})");
                    }
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine($"推送员工数据异常: {ex.Message}");
            }
        }

        // 托盘与自动流程字段（新增）
        private NotifyIcon _notifyIcon;
        private ContextMenuStrip _trayMenu;
        private ToolStripMenuItem _menuExit;
        private bool _autoStarted = false;
        private bool _allowClose = false;
        private bool _isAutoFlowSucceeded = false;
        private bool _exitHooked = false;

        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);

            if (_autoStarted) return;
            _autoStarted = true;

            try
            {
                // 初始化托盘
                InitTray();

                // Hook 退出按钮：确保点击窗体内"退出"时可真正退出
                if (!_exitHooked)
                {
                    try
                    {
                        btnExit.Click -= BtnExit_ClickWrapper; // 防重复
                    }
                    catch { }
                    btnExit.Click += BtnExit_ClickWrapper;
                    _exitHooked = true;
                }

                // 1) 加载配置并填充 UI
                LoadConfigToUIFromAppSettings();
                Application.DoEvents();

                // 2) 自动点击"添加设备"
                btnLogin_Click(this, EventArgs.Empty);
                Application.DoEvents();

                if (listViewDevice.Items.Count <= 0)
                {
                    // 未能添加设备，保持窗口显示以便排错
                    MessageBox.Show("添加设备失败：列表为空或登录失败。");
                    return;
                }

                // 3) 自动点击"全部布防"
                btn_SetAlarm_Click(this, EventArgs.Empty);
                Application.DoEvents();

                bool anyArmed = false;
                for (int i = 0; i < listViewDevice.Items.Count; i++)
                {
                    if (listViewDevice.Items[i].SubItems.Count > 2)
                    {
                        var status = listViewDevice.Items[i].SubItems[2].Text ?? string.Empty;
                        if (status.Contains("布防成功"))
                        {
                            anyArmed = true;
                            break;
                        }
                    }
                }

                if (!anyArmed)
                {
                    MessageBox.Show("布防失败：请检查设备连接或参数。");
                    return;
                }

                // 4) 全部成功，最小化到托盘
                _isAutoFlowSucceeded = true;
                MinimizeToTray();
            }
            catch (Exception ex)
            {
                MessageBox.Show("自动流程异常: " + ex.Message);
            }
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (!_allowClose)
            {
                // 拦截窗口关闭：隐藏到托盘
                e.Cancel = true;
                if (_notifyIcon != null)
                {
                    _notifyIcon.Visible = true;
                }
                this.ShowInTaskbar = false;
                this.Hide();
            }

            base.OnFormClosing(e);
        }

        // 退出按钮包装：确保允许真正关闭
        private void BtnExit_ClickWrapper(object sender, EventArgs e)
        {
            _allowClose = true;
            btnExit_Click(sender, e);
        }

        // 初始化托盘控件
        private void InitTray()
        {
            if (_notifyIcon != null) return;

            _notifyIcon = new NotifyIcon();
            _notifyIcon.Icon = SystemIcons.Application;
            _notifyIcon.Visible = false;
            _notifyIcon.Text = "KaoQinMonitor";

            _trayMenu = new ContextMenuStrip();
            _menuExit = new ToolStripMenuItem("退出");
            _menuExit.Click += (s, e) =>
            {
                _allowClose = true;
                // 复用现有退出逻辑
                btnExit_Click(this, EventArgs.Empty);
            };
            _trayMenu.Items.Add(_menuExit);
            _notifyIcon.ContextMenuStrip = _trayMenu;

            _notifyIcon.DoubleClick += (s, e) =>
            {
                ShowFromTray();
            };
        }

        // 最小化到托盘
        private void MinimizeToTray()
        {
            try
            {
                if (_notifyIcon != null)
                {
                    _notifyIcon.Visible = true;
                    _notifyIcon.BalloonTipTitle = "KaoQinMonitor";
                    _notifyIcon.BalloonTipText = "程序已最小化到托盘";
                    _notifyIcon.ShowBalloonTip(2000);
                }

                this.WindowState = FormWindowState.Minimized;
                this.ShowInTaskbar = false;
                this.Hide();
            }
            catch { }
        }

        // 从托盘恢复
        private void ShowFromTray()
        {
            try
            {
                this.Show();
                this.ShowInTaskbar = true;
                this.WindowState = FormWindowState.Normal;
                this.Activate();
                this.BringToFront();
            }
            catch { }
        }

        // 读取配置并填充到 UI
        private void LoadConfigToUIFromAppSettings()
        {
            try
            {
                var ip = ConfigurationManager.AppSettings["DeviceIP"] ?? string.Empty;
                var port = ConfigurationManager.AppSettings["DevicePort"] ?? string.Empty;
                var user = ConfigurationManager.AppSettings["Username"] ?? string.Empty;
                var pwd = ConfigurationManager.AppSettings["Password"] ?? string.Empty;

                if (!string.IsNullOrWhiteSpace(ip)) textBoxIP.Text = ip;
                if (!string.IsNullOrWhiteSpace(port)) textBoxPort.Text = port;
                if (!string.IsNullOrWhiteSpace(user)) textBoxUserName.Text = user;
                if (!string.IsNullOrWhiteSpace(pwd)) textBoxPassword.Text = pwd;
            }
            catch (Exception ex)
            {
                MessageBox.Show("读取配置失败: " + ex.Message);
            }
        }
    }
}
